//////////////////////////////////////////////////////////////////////
// CameraManager.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Camera manager
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include <ManagerBase.h>
#include <DXUTcamera.h>
#include <ITraverse.h>
#include <vector>
#include <algorithm>
#include <Camera.h>

namespace grflib
{
	namespace engine
	{
		namespace core
		{
			////////////////////////////////////////
			//GUI panel manager
			class CCameraManager : public _CManagerBase<CCamera>
			{
			public:
				CCameraManager() {}
				virtual ~CCameraManager() {}

				bool HandleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
				{
					for (std::vector<boost::shared_ptr<CCamera>>::iterator iter = m_activeCameras.begin();
						iter != m_activeCameras.end();
						++iter)
						(*iter)->MsgProc(hWnd, uMsg, wParam, lParam);
					return false;
				}

				void OnFrameMove(double fTime, float fElapsedTime) //move only active cameras
				{
					for (std::vector<boost::shared_ptr<CCamera>>::iterator iter = m_activeCameras.begin();
						iter != m_activeCameras.end();
						++iter)
					{
						(*iter)->FrameMove(fElapsedTime);
					}
				}

				HRESULT OnResize(ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
                                          const DXGI_SURFACE_DESC* pBufferSurfaceDesc)
				{
					IResizeFunc<CCamera> resizer(pd3dDevice, pSwapChain, pBufferSurfaceDesc);
					Traverse(resizer);
					return S_OK;
				}

                HRESULT OnResize(UINT width, UINT height)
                {
                    IResizeFunc1<CCamera> resizer(width, height);
                    Traverse(resizer);
                    return S_OK;
                }

				boost::shared_ptr<CCamera> &GetActiveCamera(UINT i = 0)
				{
					static boost::shared_ptr<CCamera> empty;
                    if (i >= m_activeCameras.size())
                        return empty;
					return m_activeCameras[i];
				}
				
				bool SetCurrentCamera(char *name)
				{
					boost::shared_ptr<CCamera> &pCam = FindObj(name);
					if (pCam)
					{
						std::vector<boost::shared_ptr<CCamera>>::iterator iter = 
							std::find(m_activeCameras.begin(), m_activeCameras.end(), pCam);
						if (iter != m_activeCameras.end()) //current camera must be active!
						{
							m_pCurCamera = pCam;
							return true;
						}
					}
					return false;
				}

                bool SetCurrentCamera(boost::shared_ptr<CCamera> &pCam)
                {
                    std::string name;
                    if (GetObjName(name, pCam))
                    {
                        std::vector<boost::shared_ptr<CCamera>>::iterator iter = 
                            std::find(m_activeCameras.begin(), m_activeCameras.end(), pCam);
                        if (iter != m_activeCameras.end())
                        {
                            m_pCurCamera = pCam;
                            return true;
                        }
                    }
                    return false;
                }

				boost::shared_ptr<CCamera> &GetCurrentCamera(void)
				{ return m_pCurCamera; }

				void ActivateCamera(char *name)
				{
					boost::shared_ptr<CCamera> &pCam = FindObj(name);
					if (pCam)
					{
						if (find(m_activeCameras.begin(), m_activeCameras.end(), pCam) == m_activeCameras.end())
							m_activeCameras.push_back(pCam);
					}
				}

				void DeactivateCamera(boost::shared_ptr<CCamera> &pCam)
				{
					std::vector<boost::shared_ptr<CCamera>>::iterator iter =
						find(m_activeCameras.begin(), m_activeCameras.end(), pCam);
					if (iter != m_activeCameras.end())
					{
                        (*iter).reset();
                        m_activeCameras.erase(iter);
						if ((*iter) == m_pCurCamera) //is current camera
						{
							if (m_activeCameras.size() > 0) //point to the bottom of the active cam list
								m_pCurCamera = m_activeCameras[0];
                            else
                                m_pCurCamera.reset();
						}
					}
				}

				void DeactivateCamera(char *name)
				{
					boost::shared_ptr<CCamera> &pCam = FindObj(name);
					if (pCam) DeactivateCamera(pCam);
				}

				bool AddObj(const std::string &name, boost::shared_ptr<CCamera> &pCamera)
				{
					if (_CManagerBase<CCamera>::AddObj(name, pCamera))
					{
						m_activeCameras.push_back(pCamera);
						return true;
					}
					else
						return false;
				}

                void Clear(void)
                {
                    _CManagerBase<CCamera>::Clear();
                    m_activeCameras.clear();
                    m_pCurCamera.reset();
                }

			protected:
				std::vector<boost::shared_ptr<CCamera>> m_activeCameras;
				boost::shared_ptr<CCamera> m_pCurCamera;

			};

		} //namespace core
	} //namespace engine
} //namespace grflib